<?php
/*------------------------------------------------------------------------------
this file is part of Web Application Kit http://webappkit.net
Copyright (C) 2006 J.Ducastel fredbird@fredbird.org

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
------------------------------------------------------------------------------*/

/**
* This is the webappkit µkernel
* @author J.Ducastel <fredbird@fredbird.org>
* @version 
*/
class wakMicroKernel {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	/**
	* constructor
	* @access public
	*/
	function wakMicroKernel() {
		$this->__construct();
	}/**/
	
	/**
	*
	* @access
	*/
	function __construct() {
		// starting time counter
		$this->timeCounter();
		// echo uniqid('wak');
		$this->id=uniqid('wak-');
		// setting constants
		$this->_setConstants();
		// getting basic libraries
		include(WAK_CORE_PATH.'lib.php/wak/wakservice.class.php');
		// include_once(WAK_CORE_PATH.'lib/waknamespace.class.php');
		//echo "toto";
	}/**/
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
	/**
	* serves an http request
	* serves current request by default
	* executes all events applyin to this request
	* @access public
	* @static
	* @param httpRequestBean $req
	* @return bool
	*/
	function serveRequest($req=NULL) {
		// getting self singleton
		$w=&wakMicroKernel::getSingleton();
		//echo "toto";
		// serving request
		$reqH=$w->getService('wakrequesthandler','triggeredevents');
		return $reqH->serveRequest($req);
	}/**/
	
	/**
	* Shuts down and exit
	* @access public
	* @return NULL
	*/
	function shutDown() {
		// getting self singleton
		//$w=&wak::_getSingleton();
		//echo '<p>'.wak::timecounter().'</p>';

		//ob_end_flush();
		//$deb=$w->getservice('wakdebug');
		// echo $deb->vardump($w);
		exit;
	}/**/
	
	/**
	* returns the service instance
	* @static
	* @param string name service general name
	* @param string version opt service implementation version
	* @access public
	* @return wakService
	*/
	function & getService($name, $version='') {
		// getting self singleton
		$w=&wakMicroKernel::getSingleton();
		if (!$service=&$w->_getService($name, $version)) {
			trigger_error("wak::getservice($name , $version) : failed to find service",E_USER_WARNING);
		}
		return $service;
	}/**/
	
	/**
	* just include definition file for service
	* @static
	* @access public
	* @param string name service general name
	* @param string version opt service implementation version
	* @return bool
	*/
	function defineService($name,$version='') {
		// getting self singleton
		$w=&wakMicroKernel::getSingleton();
		return $w->_defineService($name,$version);
	}/**/
	
	/**
	* at first call, defines WAK_START_TIME as reference microtime
	* after that, return spent time in seconds, with chosen precision
	* @param int $precision (default 5) 
	* @static
	* @access public
	* @return float spent time since the first call
	*/
	function timeCounter($precision=5) {
		list($usec, $sec) = explode(" ", microtime());
		$microtime=((float)$usec + (float)$sec);
		if (!defined('WAK_START_TIME'))
			define('WAK_START_TIME',$microtime);
		//echo $microtime;
		$timeCounter=$microtime-WAK_START_TIME;
		return round($timeCounter,$precision);
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function () {
		
	}/**/
/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
	/**
	* @var type desc
	*/
	var $services=array(); //service instances. keys = {name}[.{version}](.core)|(.app)
	var $output_enabled=true;
	var $output_buffer;
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
	/**
	* getting self singleton for static public methods
	* @static
	* @access private
	* @return wak
	*/
	function & getSingleton() {
		static $singleton;
		if (!isset($singleton['w'])) {
			$singleton['w']=&new wakMicroKernel();
		}
		return $singleton['w'];
	}/**/
	
	/**
	* defining core constants
	* @param
	* @access private
	* @return bool
	*/
	function _setConstants() {
		static $s; if ($s) return true;
		// core path
		//define('WAK_CORE_PATH',dirname(__FILE__).'/');
		// request
		$s=true;
		return true;
	}/**/
	
	/**
	* return service instance
	* @param string name service general name
	* @param string version opt service implementation version
	* @param bool fromCore force getting service from core
	* @access private
	* @return wakService
	*/
	function & _getService($name, $version='') {
		// checking params
		if (!is_string($name) or !is_string($version)) {
			trigger_error("wak: invalid service name $version.$name");
		}
		// getting class name = key in internal storage
		$class=$this->_serviceClass($name,$version);
		// searching or building instances
		// instance is built
		if (isset($this->services[$class]))
			return $this->services[$class];
		// including service definition file(s)
		if (!$this->_defineService($name,$version)) {
			trigger_error("wak: couldnt define service name $version.$name");
			$r=false;
			return $r;
		}
		// building instance
		$service=&new $class();
		// referencing instance
		$this->services[$class]=&$service;
		return $service;
		//
	}/**/
	
	/**
	* builds service instance
	* @param string name service general name
	* @param string version opt service implementation version
	* @param bool fromCore force getting service from core
	* @access private
	* @return wakService|false
	*/
	function & _buildServiceInstance($name, $version='', $fromCore=false) {
		// trigger_error("building $version.$name");
		// searching for definition file(s)
		// >> deport to a method with dependance supporting
		switch (true) {
			// including requested service file
			case $file=$this->_serviceFile($name, $version, $fromCore):
				// trigger_error("including $file");
				include_once($file);
				break;
			// including core service file
			case $file=$this->_serviceFile($name, $version, true):
				$fromCore=true;
				include_once($file);
				break;
			default:
				// trigger_error("file $file not found");
				$s=false;
				return $s;
		}

		// defining class name
		$class=$this->_serviceClass($name, $version); //echo "<p>$class</p>";
		// building
		$s=&new $class(); // var_dump($s);
		// referencing
		$key=$this->_serviceKey($name, $version, $fromCore);
		$this->services[$key]=&$s;
		return $s;
	}/**/
	
	/**
	* return service theoric class name
	* @param string $name
	* @param string $version
	* @access private
	* @return string
	*/
	function _serviceClass($name, $version='') {
		return $name.($version?'_'.$version:'');
	}/**/
	
	/**
	* includes service definition file, with dependances
	* @param string $name service name
	* @param string $version service flavour
	* @access private
	* @return bool
	*/
	function _defineService($name, $version='') {
		$class=$this->_serviceClass($name,$version);
		if (class_exists($class)) return true;
		// defining service class
		$file=$this->_serviceFile($name,$version);
		if (!file_exists($file)) {
			return false;
		}
		// including definition file
		include_once($file);
		if (!class_exists($class)) {
			trigger_error("wak: service $name still undefined after including $file");
			return false;
		}
		return true;
	}/**/
	
	/**
	* return service definition file name if the file exists, or false
	* @param bool fromCore getting service from core or from app
	* @param string name service general name
	* @param string version opt service implementation version
	* @access private
	* @return string|false
	*/
	function _serviceFile($name, $version='') {
		// lowercase
		$name=strtolower($name);
		$version=strtolower($version);
		// searching core-level
		$filename=WAK_CORE_PATH.'services.php/'
			.($version?$version.'.':'').$name
			.'.wakservice.php';
		if (file_exists($filename)) return $filename;
		//searching app-level
		$filename='services.php/'
			.($version?$version.'.':'').$name
			.'.wakservice.php';
		if (file_exists($filename)) return $filename;
		// not found
		trigger_error('wak: no definition file for service '.($version?$version.'.':'').$name);
		return false;
	}/**/
	

	

	
	/**
	* Enables/disables output by buffering
	* @param bool $enable
	* @access private
	* @return 
	*/
	function _outputEnabled($enable=NULL, $flush=false) {
		switch ($enable) {
			case true:
				$this->output_enabled=true;
				$this->output_buffer.=ob_get_contents();
				ob_end_clean();
				break;
			case false:
				$this->output_enabled=false;
				ob_start();
				break;
		}
		return $this->output_enabled;
	}/**/
	

	
	/**
	* 
	* @param
	* @access private
	* @return 
	* /
	function () {
		
	}/**/
	
	/**
	* 
	* @param
	* @access private
	* @return 
	* /
	function () {
		
	}/**/
}
?>
